import ast
import logging
from collections import defaultdict
from typing import Dict, List, Set, Optional, Any

from 程序核心代码.ast节点.节点分析.分析器基类 import 分析器基类
from 程序核心代码.ast节点.节点定义.基础定义.ast节点基础定义 import ast节点基础模型

logger = logging.getLogger(__name__)

class 控制流分析器(分析器基类):
    """控制流分析器类，用于分析节点间的控制流关系"""
    
    def __init__(self):
        super().__init__()
        self.控制流图: Dict[ast节点基础模型, Dict[str, Set[ast节点基础模型]]] = defaultdict(lambda: defaultdict(set))
        self.入口节点: Optional[ast节点基础模型] = None
        self.出口节点: Optional[ast节点基础模型] = None
        self.基本块: List[Set[ast节点基础模型]] = []
        self.循环信息: Dict[ast节点基础模型, Dict[str, Any]] = {}
        
    def 分析节点(self, 节点: ast节点基础模型) -> Dict[str, Any]:
        """分析指定节点的控制流关系"""
        try:
            if not self.验证节点(节点):
                return {}
                
            # 分析控制流
            self._分析控制流(节点)
            
            # 识别基本块
            self._识别基本块(节点)
            
            # 分析循环结构
            self._分析循环结构(节点)
            
            # 记录分析结果
            self.分析结果[节点._节点ID] = {
                "前驱节点": [节点._节点ID for 节点 in self.控制流图[节点]["前驱"]],
                "后继节点": [节点._节点ID for 节点 in self.控制流图[节点]["后继"]],
                "所属基本块": self._获取节点基本块索引(节点),
                "循环信息": self.循环信息.get(节点, {})
            }
            
            self.标记已分析(节点)
            return self.分析结果[节点._节点ID]
            
        except Exception as e:
            self.记录分析日志(f"控制流分析失败: {str(e)}", "error")
            return {}
            
    def _分析控制流(self, 节点: ast节点基础模型) -> None:
        """分析节点的控制流关系"""
        # 分析通过接口的控制流
        for 接口名, 接口 in 节点.节点接口.items():
            if 接口.类型 == "控制流":
                if 接口.方向 == "输出":
                    for 目标接口 in 接口.连接列表:
                        self.控制流图[节点]["后继"].add(目标接口.节点模型)
                        self.控制流图[目标接口.节点模型]["前驱"].add(节点)
                        
        # 分析AST节点的控制流
        if hasattr(节点, '_ast节点'):
            self._分析AST控制流(节点)
            
    def _分析AST控制流(self, 节点: ast节点基础模型) -> None:
        """分析AST节点的控制流关系"""
        class 控制流访问器(ast.NodeVisitor):
            def __init__(self, 外部实例):
                self.外部实例 = 外部实例
                self.当前节点 = 节点
                
            def visit_If(self, ast节点):
                # 分析if语句的控制流
                条件节点 = self.当前节点
                for 子节点 in ast节点.body:
                    主体节点 = self.外部实例.所属节点模型管理器.创建节点(子节点)
                    if 主体节点:
                        self.外部实例.控制流图[条件节点]["后继"].add(主体节点)
                        self.外部实例.控制流图[主体节点]["前驱"].add(条件节点)
                        
                for 子节点 in ast节点.orelse:
                    否则节点 = self.外部实例.所属节点模型管理器.创建节点(子节点)
                    if 否则节点:
                        self.外部实例.控制流图[条件节点]["后继"].add(否则节点)
                        self.外部实例.控制流图[否则节点]["前驱"].add(条件节点)
                        
                self.generic_visit(ast节点)
                
            def visit_While(self, ast节点):
                # 分析while循环的控制流
                循环节点 = self.当前节点
                for 子节点 in ast节点.body:
                    主体节点 = self.外部实例.所属节点模型管理器.创建节点(子节点)
                    if 主体节点:
                        self.外部实例.控制流图[循环节点]["后继"].add(主体节点)
                        self.外部实例.控制流图[主体节点]["前驱"].add(循环节点)
                        self.外部实例.控制流图[主体节点]["后继"].add(循环节点)
                        
                self.generic_visit(ast节点)
                
            def visit_For(self, ast节点):
                # 分析for循环的控制流
                循环节点 = self.当前节点
                for 子节点 in ast节点.body:
                    主体节点 = self.外部实例.所属节点模型管理器.创建节点(子节点)
                    if 主体节点:
                        self.外部实例.控制流图[循环节点]["后继"].add(主体节点)
                        self.外部实例.控制流图[主体节点]["前驱"].add(循环节点)
                        self.外部实例.控制流图[主体节点]["后继"].add(循环节点)
                        
                self.generic_visit(ast节点)
                
        访问器 = 控制流访问器(self)
        访问器.visit(节点._ast节点)
        
    def _识别基本块(self, 节点: ast节点基础模型) -> None:
        """识别控制流图中的基本块"""
        已访问 = set()
        当前块 = set()
        
        def dfs(当前节点: ast节点基础模型) -> None:
            if 当前节点 in 已访问:
                return
                
            已访问.add(当前节点)
            当前块.add(当前节点)
            
            # 检查是否需要结束当前基本块
            后继节点数 = len(self.控制流图[当前节点]["后继"])
            前驱节点数 = len(self.控制流图[当前节点]["前驱"])
            
            if 后继节点数 > 1 or 前驱节点数 > 1:
                if 当前块:
                    self.基本块.append(当前块.copy())
                    当前块.clear()
                    
            # 继续访问后继节点
            for 后继节点 in self.控制流图[当前节点]["后继"]:
                dfs(后继节点)
                
        dfs(节点)
        if 当前块:
            self.基本块.append(当前块)
            
    def _分析循环结构(self, 节点: ast节点基础模型) -> None:
        """分析控制流图中的循环结构"""
        已访问 = set()
        当前路径 = []
        
        def dfs(当前节点: ast节点基础模型) -> None:
            if 当前节点 in 当前路径:
                # 发现循环
                循环起点 = 当前路径.index(当前节点)
                循环节点集 = set(当前路径[循环起点:])
                self._记录循环信息(循环节点集)
                return
                
            if 当前节点 in 已访问:
                return
                
            已访问.add(当前节点)
            当前路径.append(当前节点)
            
            for 后继节点 in self.控制流图[当前节点]["后继"]:
                dfs(后继节点)
                
            当前路径.pop()
            
        dfs(节点)
        
    def _记录循环信息(self, 循环节点集: Set[ast节点基础模型]) -> None:
        """记录循环的相关信息"""
        for 节点 in 循环节点集:
            self.循环信息[节点] = {
                "是循环成员": True,
                "循环ast节点基础模型": [节点._节点ID for 节点 in 循环节点集],
                "循环入口": next(iter(循环节点集))._节点ID,
                "循环大小": len(循环节点集)
            }
            
    def _获取节点基本块索引(self, 节点: ast节点基础模型) -> Optional[int]:
        """获取节点所属的基本块索引"""
        for i, 块 in enumerate(self.基本块):
            if 节点 in 块:
                return i
        return None
        
    def 获取控制流图(self) -> Dict[str, Any]:
        """获取完整的控制流图"""
        return {
            节点._节点ID: {
                "前驱": [前驱._节点ID for 前驱 in 流向["前驱"]],
                "后继": [后继._节点ID for 后继 in 流向["后继"]]
            }
            for 节点, 流向 in self.控制流图.items()
        }
        
    def 获取基本块信息(self) -> List[List[str]]:
        """获取基本块信息"""
        return [[节点._节点ID for 节点 in 块] for 块 in self.基本块]
        
    def 重置(self) -> None:
        """重置分析器状态"""
        super().重置()
        self.控制流图.clear()
        self.入口节点 = None
        self.出口节点 = None
        self.基本块.clear()
        self.循环信息.clear()
        
    def __str__(self) -> str:
        """返回控制流分析器的字符串表示"""
        return f"控制流分析器(节点数={len(self.控制流图)}, 基本块数={len(self.基本块)})" 